package nioserver;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * 多路复用分发器
 * 
 * DemultiPlexer 继承了 Thread 类，在 signal 方法中，调用 selector.select() 函数，
 * 该函数等待一个 SocketChannel 中的事件出现才返回。在 signal 方法中，对两种事件感兴趣，一个是 OP_ACCEPT, 一个是 OP_READ ，
 * 当收到 OP_ACCEPT 事件时，把 SelectionKey 中的 channel 中转化成 ServerSocketChannel ，并且掉中 ServerSocketChannel.accpet() 方法，
 * 返回一个 SocketChannel ，然后在设置成 non-blocking IO 模式，最后注册 OP_READ 事件。
 * 当收到一个 OP_READ 事件时，想 Dispatcher 注册这个事件，让 Dispatcher 去启动一个线程去处理该事件，处理完成后，并把该事件从 Selector 中撤销。
 * 
 * @author Xinz
 *
 */
public class NIODemultiPlexer extends Thread{

	private Selector selector;
	private NIODispatcher dispatcher;
	
	public NIODemultiPlexer(Selector selector, NIODispatcher dispatcher) {
		this.selector = selector;
		this.dispatcher = dispatcher;
	}
	@Override
	public void run() {
		for(;;) {
			try {
				signal();
			}
			catch(IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void signal() throws IOException {
		int c = selector.select();
		if(c <= 0)
			return;
		Iterator<SelectionKey> keysIt = selector.selectedKeys().iterator();
		while(keysIt.hasNext()) {
			SelectionKey key = keysIt.next();
			keysIt.remove();
			if(key.isValid()) {
				if(key.isAcceptable()) {
					accept(key);
				}
				else if(key.isReadable()) {
					dispatcher.register(key);
				}
			}
		}
	}
	
	private void accept(SelectionKey key) throws IOException {
		ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
		SocketChannel channel = ssc.accept();
		channel.configureBlocking(false);
		channel.register(selector, SelectionKey.OP_READ);
//		key.cancel();
	}
	
}
